import { create } from 'zustand'
import type { CSSProperties } from 'react'
export interface Component {
    id: number,
    name: string,
    props: any,
    desc: string,
    children?: Component[],
    parentId?: number,
    styles?: CSSProperties,//组件样式
}
export interface State {
    components: Component[]
    curComponentId: number | null,
    curComponent: Component | null,
    mode: 'edit' | 'preview',//表示编辑和预览状态
}
export interface Action {
    addComponent: (component: any, parentId: number) => void
    //parentId父容器的id，知道子组件加到哪个父容器内
    deleteComponent: (componentId: number) => void
    updateComponentProps: (componentId: number, props: any) => void//更新组件属性
    updateComponentStyles: (componentId: number, styles: CSSProperties) => void//更新组件样式
    setCurComponentId: (componentId: number) => void//设置当前组件的id
    setMode: (mode: 'edit' | 'preview') => void//设置模式
}
export const useComponentsStore = create<State & Action>((set, get) => ({//set：触发视图更新 get：获取当前状态(不会触发组件渲染)
    //数据
    components: [//整个项目的json数据
        {
            id: 1,
            name: 'Page',
            props: {},
            desc: '页面',
        }
    ],
    mode: 'edit',//表示编辑和预览状态
    curComponentId: null,//鼠标点击组件时的id
    curComponent: null,//鼠标点击组件时的组件对象

    //方法
    addComponent: (component, parentId) => {//本质上就是将一个对象添加到另一个对象中(json对象)
        set((state) => {
            if (parentId) {//如果父容器id存在
                //获取父级对象
                //引用getComponentById函数，将父组件id和state.components（实际上就是刚刚定义的components[]数组）传入函数中，获取到父组件对象parentComponent
                const parentComponent = getComponentById(parentId, state.components)

                //如果父组件对象存在，执行以下三元运算符
                if (parentComponent) {
                    parentComponent.children ? parentComponent.children.push(component) : parentComponent.children = [component]//（因为children属性的值为数组）
                    //如果父组件有children属性，直接push，没有则创建，并将component放到数组内后赋值
                }
                component.parentId = parentId//设置添加的组件对象的父组件id
                return {
                    components: [...state.components]
                }
            }
            return {
                components: [...state.components, component]
                //如果没有父级，则直接添加到仓库最外层：
                // 1. 使用展开运算符将原state.components数组展开
                // 2. 将新组件component追加到末尾
                // 3. 组合成一个全新的数组
                // 4. 赋值给components属性

            }
        })
    },
    deleteComponent: (componentId) => {//在整个json对象中找到某个子对象的id，然后删除
        if (!componentId) return
        //拿到要删除的子组件
        //调用getComponentById方法就能拿到state（其实get().components就是state.components,目的都是拿到仓库中的components[]）
        const component = getComponentById(componentId, get().components)
        //如果子组件有父组件的id
        if (component?.parentId) {
            //拿到要删除的子组件的父组件
            const parentComponent = getComponentById(component.parentId, get().components)
            if (parentComponent) {
                //使用filter方法对父组件的children数组进行过滤，将id不等于要删除的子组件id的子组件对象组成一个新数组返回
                parentComponent.children = parentComponent.children?.filter((item) => item.id !== componentId)
            }
            //引用set方法触发试图更新和重新渲染，将过滤之后的数组赋值给components[]
            set({
                components: [...get().components]
            })
        }
    },
    //更新组件属性
    updateComponentProps: (componentId, props) => {//传入组件id和要添加的属性
        set((state) => {
            //获取要操作的组件
            const component = getComponentById(componentId, state.components)
            if (component) {//如果找到了要操作的组件对象
                component.props = { ...component.props, ...props }//将旧属性和新属性合并
                return {
                    //将更新后的conponents解构赋值为新的components，也就创建了一个新的引用，以达到视图更新的目的s
                    components: [...state.components]
                }
            }
            //如果没有找到组件对象，则也创建了一个新的引用，将原来的components[]解构赋值给新的components，以达到视图更新的目的
            return { components: [...state.components] }
        })
    },
    updateComponentStyles: (componentId, styles) => {//更新组件样式
        set((state) => {
            //获取要操作的组件
            const component = getComponentById(componentId, state.components)
            if (component) {
                component.styles = { ...component.styles, ...styles }//将旧属性和新属性合并
                return {
                    components: [...state.components]//返回更新后的components
                }
            }
            return { components: [...state.components] }
        })
    },
    setCurComponentId: (componentId) => {//将curComponentId设置为当前选中的组件的id
        set((state) => ({
            curComponentId: componentId,
            curComponent: getComponentById(componentId, state.components)
        }))
    },
    setMode: (mode) => {//将仓库内的mode的值改为接收到的mode的值
        set(() => ({
            mode: mode
        }))
    },

}))
export function getComponentById(id: number | null, components: Component[]): Component | null {//输入自己或父组件的id，找到自己或父组件
    if (!id) return null
    for (const component of components) {
        if (component.id === id) {//如果最外层可以找到所要的组件，则直接返回
            return component
        }
        if (component.children && component.children.length > 0) {//如果最外层找不到，则一步一步向下递归
            const result = getComponentById(id, component.children)
            if (result) {
                return result
            }
        }
    }
    return null
}


